<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 5.4.0">


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">



<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.15.4/css/all.min.css" integrity="sha256-mUZM63G8m73Mcidfrv5E+Y61y7a12O5mW4ezU3bxqW4=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/animate.css@3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">

<script class="next-config" data-name="main" type="application/json">{"hostname":"tallgy.gitee.io","root":"/","images":"/images","scheme":"Muse","darkmode":false,"version":"8.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":false,"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果：${query}","hits_time":"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）","hits":"找到 ${hits} 个搜索结果"}}</script><script src="/js/config.js"></script>
<meta name="description" content="Proxy 和 defineproperty 的区别和使用​        首先我们学习了 vue 的响应式之后就会知道，vue2 的响应式是根据 Object.defineproperty 进行的处理，通过编写里面的 getter 和 setter 方法。在getter 和 setter 方法里面进行了处理。getter 方法里面将对应的DOM加入了 dep数组，然后  data数据通过使用 o">
<meta property="og:type" content="article">
<meta property="og:title" content="Proxy和defineproperty">
<meta property="og:url" content="http://tallgy.gitee.io/2022/03/01/JavaScript/%E5%AF%B9%E8%B1%A1/Proxy%E5%92%8Cdefineproperty/index.html">
<meta property="og:site_name" content="tallgy&#39;s blog">
<meta property="og:description" content="Proxy 和 defineproperty 的区别和使用​        首先我们学习了 vue 的响应式之后就会知道，vue2 的响应式是根据 Object.defineproperty 进行的处理，通过编写里面的 getter 和 setter 方法。在getter 和 setter 方法里面进行了处理。getter 方法里面将对应的DOM加入了 dep数组，然后  data数据通过使用 o">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2022-03-01T14:55:17.000Z">
<meta property="article:modified_time" content="2023-06-25T08:57:29.338Z">
<meta property="article:author" content="tallgy">
<meta property="article:tag" content="随笔">
<meta property="article:tag" content="JavaScript">
<meta name="twitter:card" content="summary">


<link rel="canonical" href="http://tallgy.gitee.io/2022/03/01/JavaScript/%E5%AF%B9%E8%B1%A1/Proxy%E5%92%8Cdefineproperty/">



<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":false,"isPost":true,"lang":"zh-CN","comments":true,"permalink":"http://tallgy.gitee.io/2022/03/01/JavaScript/%E5%AF%B9%E8%B1%A1/Proxy%E5%92%8Cdefineproperty/","path":"2022/03/01/JavaScript/对象/Proxy和defineproperty/","title":"Proxy和defineproperty"}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>Proxy和defineproperty | tallgy's blog</title>
  




  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>
</head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏" role="button">
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <h1 class="site-title">tallgy's blog</h1>
      <i class="logo-line"></i>
    </a>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>







</div>
        
  
  <div class="toggle sidebar-toggle" role="button">
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
  </div>

  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
            <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#Proxy-%E5%92%8C-defineproperty-%E7%9A%84%E5%8C%BA%E5%88%AB%E5%92%8C%E4%BD%BF%E7%94%A8"><span class="nav-number">1.</span> <span class="nav-text">Proxy 和 defineproperty 的区别和使用</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#Object-defineproperty"><span class="nav-number">1.1.</span> <span class="nav-text">Object.defineproperty</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#handler-setPrototypeOf"><span class="nav-number">1.1.0.1.</span> <span class="nav-text">handler.setPrototypeOf()</span></a></li></ol></li></ol></li></ol></li></ol></div>
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author site-overview-item animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">tallgy</p>
  <div class="site-description" itemprop="description">只是一个知识的搬运工</div>
</div>
<div class="site-state-wrap site-overview-item animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
        <a href="/archives/">
          <span class="site-state-item-count">107</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
          <a href="/categories/">
        <span class="site-state-item-count">32</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
          <a href="/tags/">
        <span class="site-state-item-count">74</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>



        </div>
      </div>
    </div>
  </aside>
  <div class="sidebar-dimmer"></div>


    </header>

    
  <div class="back-to-top" role="button" aria-label="返回顶部">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


    <div class="main-inner post posts-expand">


  


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://tallgy.gitee.io/2022/03/01/JavaScript/%E5%AF%B9%E8%B1%A1/Proxy%E5%92%8Cdefineproperty/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="tallgy">
      <meta itemprop="description" content="只是一个知识的搬运工">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="tallgy's blog">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          Proxy和defineproperty
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2022-03-01 22:55:17" itemprop="dateCreated datePublished" datetime="2022-03-01T22:55:17+08:00">2022-03-01</time>
    </span>
      <span class="post-meta-item">
        <span class="post-meta-item-icon">
          <i class="far fa-calendar-check"></i>
        </span>
        <span class="post-meta-item-text">更新于</span>
        <time title="修改时间：2023-06-25 16:57:29" itemprop="dateModified" datetime="2023-06-25T16:57:29+08:00">2023-06-25</time>
      </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/JavaScript/" itemprop="url" rel="index"><span itemprop="name">JavaScript</span></a>
        </span>
          ，
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/JavaScript/%E9%9A%8F%E7%AC%94/" itemprop="url" rel="index"><span itemprop="name">随笔</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
        <h1 id="Proxy-和-defineproperty-的区别和使用"><a href="#Proxy-和-defineproperty-的区别和使用" class="headerlink" title="Proxy 和 defineproperty 的区别和使用"></a>Proxy 和 defineproperty 的区别和使用</h1><p>​        首先我们学习了 vue 的响应式之后就会知道，vue2 的响应式是根据 Object.defineproperty 进行的处理，通过编写里面的 getter 和 setter 方法。在getter 和 setter 方法里面进行了处理。getter 方法里面将对应的DOM加入了 dep数组，然后</p>
<ul>
<li>data数据通过使用 observer 转换成了 getter/setter 形式的来追踪变化。</li>
<li>当通过 watcher 读取到数据时，会触发到 getter 将其添加到 依赖中。</li>
<li>当数据发生变化时，会触发setter，然后想 dep 中的依赖（watcher） 发送通知。</li>
<li>watcher 接收到通知之后，则会发送通知。然后便会触发视图的更新。</li>
</ul>
<p>​        但是同时 Object.defineproperty 也有对应的缺点，比如这个是针对对象进行的监听，只能监听到对象的改变，而不能监听到数组的变化。</p>
<p>​        所以就有了 vue3 使用的 proxy，Proxy 对象用于创建一个对象的代理，从而实现基本操作的拦截和自定义（如属性查找、赋值、枚举、函数调用等）。proxy的特点是，可以深度监听，并且可以监听 新增和删除的属性。还可以监听数组的变化。</p>
<h2 id="Object-defineproperty"><a href="#Object-defineproperty" class="headerlink" title="Object.defineproperty"></a>Object.defineproperty</h2><ul>
<li><p>这个方法会直接 在一个对象上定义一个新属性，或者修改一个一个对象的现有属性，并返回此对象。</p>
</li>
<li><p>```<br>const object1 = {};</p>
<p>Object.defineProperty(object1, ‘property1’, {<br>  value: 42,<br>  writable: false<br>});</p>
<p>object1.property1 = 77;<br>// throws an error in strict mode</p>
<p>console.log(object1.property1);<br>// expected output: 42</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">* Object.defineProperty(obj, prop, descriptor)</span><br><span class="line"></span><br><span class="line">* 参数</span><br><span class="line"></span><br><span class="line">  * obj： 要定义的对象</span><br><span class="line">  * prop： 要定义或修改的属性的名称或者 Symbol</span><br><span class="line">  * descriptor： 要定义或修改的属性描述符。</span><br><span class="line"></span><br><span class="line">* 返回值： 被传递给函数的对象。</span><br><span class="line"></span><br><span class="line">&gt; 备注：在ES6中，由于 Symbol类型的特殊性，用Symbol类型的值来做对象的key与常规的定义或修改不同，而Object.defineProperty 是定义key为Symbol的属性的方法之一。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">简单示例：</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>const obj = {<br>a: 1,<br>}</p>
</li>
</ul>
<p>Object.defineProperty(obj, ‘b’, {<br>  value: 2,<br>})</p>
<p>Object.defineProperty(obj, ‘a’, {<br>  get() {<br>    return 1;<br>  }<br>})</p>
<p>注意点：<br>数据描述符和存取描述符不能混合使用</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">### 数据描述符 和 存储描述符 </span><br><span class="line"></span><br><span class="line">| `configurable` | `enumerable` | `value` | `writable` | `get`  | `set`  |        |</span><br><span class="line">| -------------- | ------------ | ------- | ---------- | ------ | ------ | ------ |</span><br><span class="line">| 数据描述符     | 可以         | 可以    | 可以       | 可以   | 不可以 | 不可以 |</span><br><span class="line">| 存取描述符     | 可以         | 可以    | 不可以     | 不可以 | 可以   | 可以   |</span><br><span class="line"></span><br><span class="line">​		简单来说，就是数据描述符和存储描述符是不能混用的。混用会报错。</span><br><span class="line"></span><br><span class="line">* 数据描述符：value， writable</span><br><span class="line">* 存取描述符： get， set</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">​		那么我们可以知道，因为数据描述符和存取描述符不能同时进行创建和使用。我们可以查看Vue2的源码，Vue2里面是通过 defineReactive 进行创建的响应式，一个 defineReactive 代表的就是一个value，内部会维护一个 Dep，通过 Dep.depend() 和 Dep.notify 来进行依赖添加和 通知。</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>observe(方法) —()—&gt;&gt; Observer(类) —( walk )—&gt;&gt; defineReactive(方法) —(line:178)—&gt;&gt; observe</p>
<p>就是这样的一个递归形式，从 observe 里面通过判断 不是对象 或者 属于VNode来结束递归</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure>
<p>// 注意: defineProperty 的get 方法是可以重复进行定义的。</p>
<p>const property = Object.getOwnPropertyDescriptor(obj, key);</p>
<p>const getter = property.get</p>
<p>Object.defineProperty(obj, key, {<br>    get() {<br>        const value = getter.call(obj)</p>
<pre><code>    // 处理响应式
    ...
    
    return value
&#125;
</code></pre>
<p>})</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure>
<p>// 同时记住，不能这样写，会出现，无限递归的情况，vue2 的写法是，将getter方法取出来，直接运行getter方法。<br>Object.defineProperty(o, ‘a’, {<br>  get() {<br>    console.log(‘q’)<br>    return o[‘a’]<br>  }<br>})</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">## Proxy</span><br><span class="line"></span><br><span class="line">​		**Proxy** 对象用于创建一个对象的代理，从而实现基本操作的拦截和自定义（如属性查找、赋值、枚举、函数调用等）。</span><br><span class="line"></span><br><span class="line">语法</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>const p = new Proxy(target, handler)</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">### Proxy.revocable</span><br><span class="line"></span><br><span class="line">​		与此对应的还有一个 Proxy.revocable 方法，它的使用和 new Proxy 基本一样，但是它的返回是一个包含了 代理对象本身和它的撤销方法的可撤销 Proxy 对象。</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>Proxy.revocable(target, handler)</p>
<p>返回一个对象，包含了 proxy(代理对象本身) 和 revoke(撤销方法)</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">​		注意：</span><br><span class="line"></span><br><span class="line">​		一旦某个代理对象被撤销，它将变得几乎完全不可调用，在它身上执行任何的**可代理操作**都会抛出 [`TypeError`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/TypeError) 异常（注意，可代理操作一共有 [`14 种`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy#methods_of_the_handler_object)，执行这 14 种操作以外的操作不会抛出异常）。一旦被撤销，这个代理对象便不可能被直接恢复到原来的状态，同时和它关联的**目标对象**以及**处理器对象**都有可能被垃圾回收掉。再次调用撤销方法 `revoke()` 则不会有任何效果，但也不会报错。</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>// 定义的 handler，这里定义了一个get方法，如果 prop 不存在于<br>const handler = {<br>    get: function(obj, prop) {<br>        return prop in obj ? obj[prop] : 37;<br>    }<br>};</p>
<p>const p = new Proxy({}, handler);<br>p.a = 1;<br>p.b = undefined;</p>
<p>console.log(p.a, p.b);      // 1, undefined<br>console.log(‘c’ in p, p.c); // false, 37</p>
<p>使用 revocable 进行创建一个可撤销的Proxy代理。<br>const revocable = Proxy.revocable({}, handler)<br>const proxy = revocable.proxy<br>revocable.revoke();</p>
<p>console.log(proxy.foo); // 抛出 TypeError<br>proxy.foo = 1           // 还是 TypeError<br>delete proxy.foo;       // 又是 TypeError<br>typeof proxy            // “object”，因为 typeof 不属于可代理操作</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">​		和 Object.defineproperty 一样创建多个get方法的情况</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>const obj = {}</p>
<p>let p = new Proxy(obj, {<br>  get(target, prop) {<br>    console.log(target)<br>    console.log(prop)<br>    return target[prop]<br>  }<br>})</p>
<p>p = new Proxy(p, {<br>  get(target, prop) {<br>    console.log(‘target’, target)<br>    console.log(‘prop’, prop)<br>    return target[prop]<br>  }<br>})</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">​		通过 Proxy 和 Object.defineproperty 的使用，我们可以知道几个不同的地方</span><br><span class="line"></span><br><span class="line">* Proxy的get方法带有参数，第一个是target，第二个prop。有的携带第三个参数newValue，defineproperty：不携带参数。</span><br><span class="line">* Proxy的get方法里面，target[prop]，不会再次触发get方法。defineproprety里面如果再次使用 target[prop] 会多次触发get方法。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">### Proxy 的方法</span><br><span class="line"></span><br><span class="line">#### handler.apply() </span><br><span class="line"></span><br><span class="line">**`handler.apply()`** 方法用于拦截函数的调用。</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>var p = new Proxy(target, {<br>  apply: function(target, thisArg, argumentsList) {<br>  }<br>});</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">参数：</span><br><span class="line"></span><br><span class="line">* target: 目标对象</span><br><span class="line">* thisArg： 被调用时的上下文对象</span><br><span class="line">* argumentsList： 被调用时的参数数组</span><br><span class="line"></span><br><span class="line">返回值：</span><br><span class="line"></span><br><span class="line">* 可以返回任何值</span><br><span class="line"></span><br><span class="line">返回值就是显示的内容</span><br><span class="line"></span><br><span class="line">拦截：</span><br><span class="line"></span><br><span class="line">- `proxy(...args)`</span><br><span class="line">- [`Function.prototype.apply()`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/apply) 和 [`Function.prototype.call()`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/call)</span><br><span class="line">- [`Reflect.apply()`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect/apply)</span><br><span class="line"></span><br><span class="line">约束：</span><br><span class="line"></span><br><span class="line">​		如果违反了以下约束，代理将抛出一个TypeError：</span><br><span class="line"></span><br><span class="line">​		`target`必须是可被调用的。也就是说，它必须是一个函数对象。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#### handler.construct()</span><br><span class="line"></span><br><span class="line">​		`**handler.construct()**` 方法用于拦截[`new`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/new) 操作符. 为了使new操作符在生成的Proxy对象上生效，用于初始化代理的目标对象自身必须具有[[Construct]]内部方法（即 `new target` 必须是有效的）。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#### handler.defineProperty()</span><br><span class="line"></span><br><span class="line">​		**`handler.defineProperty()`** 用于拦截对对象的 [`Object.defineProperty()`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty) 操作。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#### handler.deleteProperty()</span><br><span class="line"></span><br><span class="line">​		**`handler.deleteProperty()`** 方法用于拦截对对象属性的 [`delete`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/delete) 操作。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#### handler.get()</span><br><span class="line"></span><br><span class="line">​		**`handler.get()`** 方法用于拦截对象的读取属性操作。</span><br><span class="line"></span><br><span class="line">​		我们目前就先了解这个，因为这个就是vue3的架构里面使用的响应式的原理。</span><br><span class="line"></span><br><span class="line">语法:</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>var p = new Proxy(target, {<br>  get: function(target, property, receiver) {<br>  }<br>});</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">参数:</span><br><span class="line"></span><br><span class="line">* target：目标对象</span><br><span class="line">* property：被获取的属性名</span><br><span class="line">* receiver：Proxy或者继承Proxy的对象</span><br><span class="line"></span><br><span class="line">返回值:</span><br><span class="line"></span><br><span class="line">​		可以返回任何值。</span><br><span class="line"></span><br><span class="line">拦截：</span><br><span class="line"></span><br><span class="line">​		该方法会拦截目标对象的以下操作:</span><br><span class="line"></span><br><span class="line">- 访问属性: `proxy[foo]和` `proxy.bar`</span><br><span class="line"></span><br><span class="line">- 访问原型链上的属性: `Object.create(proxy)[foo]`</span><br><span class="line"></span><br><span class="line">- [`Reflect.get()`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect/get)</span><br><span class="line"></span><br><span class="line">  - `**Reflect**`**`.get()`**方法与从 对象 (`target[propertyKey]`) 中读取属性类似，但它是通过一个函数执行来操作的。</span><br><span class="line"></span><br><span class="line">  - ```</span><br><span class="line">    // Object</span><br><span class="line">    var obj = &#123; x: 1, y: 2 &#125;;</span><br><span class="line">    Reflect.get(obj, &quot;x&quot;); // 1</span><br><span class="line">    </span><br><span class="line">    // Array</span><br><span class="line">    Reflect.get([&quot;zero&quot;, &quot;one&quot;], 1); // &quot;one&quot;</span><br><span class="line">    </span><br><span class="line">    // Proxy with a get handler</span><br><span class="line">    var x = &#123;p: 1&#125;;</span><br><span class="line">    var obj = new Proxy(x, &#123;</span><br><span class="line">      get(t, k, r) &#123; return k + &quot;bar&quot;; &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">    Reflect.get(obj, &quot;foo&quot;); // &quot;foobar&quot;</span><br></pre></td></tr></table></figure>

<p>约束：</p>
<p>​        如果违背了以下的约束，proxy会抛出 <a target="_blank" rel="noopener" href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/TypeError"><code>TypeError</code></a>:</p>
<ul>
<li><p>如果要访问的目标属性是不可写以及不可配置的，则返回的值必须与该目标属性的值相同。</p>
<ul>
<li><p>意思就是说，对于 writeable 和 configurable 为 false，则返回值必须要相等，否则报错。</p>
</li>
<li><p>```<br>Object.defineProperty(obj, ‘b’, {<br>  value: 2,<br>  writable: false<br>})</p>
<p>let p = new Proxy(obj, {<br>  get(target, prop) {</p>
<pre><code>return 21;
</code></pre>
<p>  }<br>})</p>
<p>p.b 会报错， 因为返回值不相等，但是如果返回值改为相等就不会报错。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">    </span><br><span class="line"></span><br><span class="line">- 如果要访问的目标属性没有配置访问方法，即get方法是undefined的，则返回值必须为undefined。</span><br><span class="line"></span><br><span class="line">  - 大概意思是不可访问的情况下，访问的get返回需要为 undefined。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#### handler.getOwnPropertyDescriptor()</span><br><span class="line"></span><br><span class="line">​		**`handler.getOwnPropertyDescriptor()`** 方法是 [`Object.getOwnPropertyDescriptor()`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor) 的钩子。</span><br><span class="line"></span><br><span class="line">​		**`Object.getOwnPropertyDescriptor()`** 方法返回指定对象上一个自有属性对应的属性描述符。（自有属性指的是直接赋予该对象的属性，不需要从原型链上进行查找的属性）</span><br><span class="line"></span><br><span class="line">语法：</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>var p = new Proxy(target, {<br>getOwnPropertyDescriptor: function(target, prop) {<br>}<br>});</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">拦截：</span><br><span class="line"></span><br><span class="line">​		这个陷阱可以拦截这些操作：</span><br><span class="line"></span><br><span class="line">- [`Object.getOwnPropertyDescriptor()`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor)</span><br><span class="line">- [`Reflect.getOwnPropertyDescriptor()`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect/getOwnPropertyDescriptor)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#### handler.getPrototypeOf()</span><br><span class="line"></span><br><span class="line">​		**`handler.getPrototypeOf()`** 是一个代理（Proxy）方法，当读取代理对象的原型时，该方法就会被调用。</span><br><span class="line"></span><br><span class="line">​		Object.getPrototypeOf， 返回的是参数的原型。</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>const handler = {<br>getPrototypeOf(target) {<br>return monsterPrototype;<br>}<br>};</p>
</li>
</ul>
</li>
</ul>
<p>简单来说，返回值就是原型。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#### handler.has()</span><br><span class="line"></span><br><span class="line">​		 **`handler.has()`** 方法是针对 [`in`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/in) 操作符的代理方法。</span><br><span class="line"></span><br><span class="line">​		如果指定的属性在指定的对象或其原型链中，则**`in` 运算符**返回`true`。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#### handler.isExtensible()</span><br><span class="line"></span><br><span class="line">​		**handler.isExtensible()** 方法用于拦截对对象的Object.isExtensible()。</span><br><span class="line"></span><br><span class="line">​		`**Object.isExtensible()**` 方法判断一个对象是否是可扩展的（是否可以在它上面添加新的属性）。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#### handler.ownKeys()</span><br><span class="line"></span><br><span class="line">​		**`handler.ownKeys()`** 方法用于拦截 [`Reflect.ownKeys()`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect/ownKeys).</span><br><span class="line"></span><br><span class="line">​		静态方法 `**Reflect**`**`.ownKeys()`** 返回一个由目标对象自身的属性键组成的数组。</span><br><span class="line"></span><br><span class="line">描述：</span><br><span class="line"></span><br><span class="line">​		Reflect.ownKeys` 方法返回一个由目标对象自身的属性键组成的数组。它的返回值等同于`Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))。</span><br><span class="line"></span><br><span class="line">​		getOwnPropertyNames：返回自身属性，包括不可枚举，但不包括 Symbol 属性</span><br><span class="line"></span><br><span class="line">​		getOwnPropertySymbols：返回自身的 Symbol 属性</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#### handler.preventExtensions()</span><br><span class="line"></span><br><span class="line">​		**`handler.preventExtensions()`** 方法用于设置对[`Object.preventExtensions()`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/preventExtensions)的拦截</span><br><span class="line"></span><br><span class="line">​		`**Object.preventExtensions()**`方法让一个对象变的不可扩展，也就是永远不能再添加新的属性。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#### handler.set()</span><br><span class="line"></span><br><span class="line">​		`**handler.set()**` 方法是设置属性值操作的捕获器。</span><br><span class="line"></span><br><span class="line">语法：</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>const p = new Proxy(target, {<br>  set: function(target, property, value, receiver) {<br>  }<br>});</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">参数：</span><br><span class="line"></span><br><span class="line">​		以下是传递给 `set()` 方法的参数。`this` 绑定在 handler 对象上。</span><br><span class="line"></span><br><span class="line">* target： 目标对象</span><br><span class="line"></span><br><span class="line">* property： 被设置的属性名或者 Symbol</span><br><span class="line"></span><br><span class="line">* value： 新的属性值</span><br><span class="line"></span><br><span class="line">* receiver： 最初被调用的对象。通常是 proxy 本身，但 handler 的 set 方法也有可能在原型链上，或以其他方式被间接地调用（因此不一定是 proxy 本身）。</span><br><span class="line"></span><br><span class="line">* ```</span><br><span class="line">  const monster1 = &#123; eyeCount: 4 &#125;;</span><br><span class="line">  </span><br><span class="line">  const m = &#123;</span><br><span class="line">    a: 12,</span><br><span class="line">  &#125;</span><br><span class="line">  const handler2 = &#123;</span><br><span class="line">    set(o, p, v, re) &#123;</span><br><span class="line">      // console.log(this)</span><br><span class="line">      // console.log(re)</span><br><span class="line">  </span><br><span class="line">      return true</span><br><span class="line">    &#125;,</span><br><span class="line">    a: 2,</span><br><span class="line">  &#125;</span><br><span class="line">  const pro2 = new Proxy(m, handler2)</span><br><span class="line">  </span><br><span class="line">  monster1.__proto__ = pro2</span><br><span class="line">  </span><br><span class="line">  // ok</span><br><span class="line">  monster1.d = 123</span><br><span class="line">  // not ok</span><br><span class="line">  monster1.b = 321</span><br><span class="line">  monster1.c = 321</span><br><span class="line">  </span><br><span class="line">  console.log(Object.getOwnPropertyNames(monster1), monster1.b)</span><br><span class="line">  console.log(Object.getOwnPropertyNames(pro2), pro2.b)</span><br><span class="line">  </span><br><span class="line">  // 不理解为什么，不行</span><br><span class="line">  // 目前来说，就是 children 的原型的指向是一个 proxy的实例，然后proxy的实例存在一个set方法。然后再 children设置属性的时候，出现了children不含这个属性，所以就会出现，调用proxy实例，方法。但是我返回值为true，但是还是没有赋值成功。但从案例来说，就是在原型修改之前和之后出现的变化。</span><br></pre></td></tr></table></figure>



<h4 id="handler-setPrototypeOf"><a href="#handler-setPrototypeOf" class="headerlink" title="handler.setPrototypeOf()"></a>handler.setPrototypeOf()</h4><p>​        <strong><code>handler.setPrototypeOf()</code></strong> 方法主要用来拦截 <a target="_blank" rel="noopener" href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf"><code>Object.setPrototypeOf()</code></a>.</p>
<p>​        <strong>Object.setPrototypeOf()</strong> 方法设置一个指定的对象的原型 ( 即, 内部[[Prototype]]属性）到另一个对象或  <a target="_blank" rel="noopener" href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/null"><code>null</code></a>。</p>

    </div>

    
    
    

    <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/%E9%9A%8F%E7%AC%94/" rel="tag"># 随笔</a>
              <a href="/tags/JavaScript/" rel="tag"># JavaScript</a>
          </div>

        

          <div class="post-nav">
            <div class="post-nav-item">
                <a href="/2022/02/18/React/React-Hook/" rel="prev" title="React-Hook">
                  <i class="fa fa-chevron-left"></i> React-Hook
                </a>
            </div>
            <div class="post-nav-item">
                <a href="/2022/03/03/JavaScript/%E5%AF%B9%E8%B1%A1/Object-proto/" rel="next" title="Object.__proto__">
                  Object.__proto__ <i class="fa fa-chevron-right"></i>
                </a>
            </div>
          </div>
    </footer>
  </article>
</div>






</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">


<div class="copyright">
  &copy; 
  <span itemprop="copyrightYear">2023</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">tallgy</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.js.org/muse/" rel="noopener" target="_blank">NexT.Muse</a> 强力驱动
  </div>

    </div>
  </footer>

  
  <script src="https://cdn.jsdelivr.net/npm/animejs@3.2.1/lib/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/schemes/muse.js"></script><script src="/js/next-boot.js"></script>

  





  





</body>
</html>
